home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2004 #11 / Amiga Plus CD - 2004 - No. 11.iso / AmiSoft / Util / crypt / sign7800.lha / sign7800.c < prev    next >
Text File  |  2004-06-20  |  17KB  |  761 lines

  1. // sign7800.c
  2. // Encrypts a digital signature for Atari 7800 cartridges.
  3. // Original version 2004-06-20 by Bruce Tomlin
  4.  
  5. #include <stdio.h>
  6. #include <ctype.h>
  7. #include <stdlib.h>
  8. #include <unistd.h>
  9. #include <string.h>
  10.  
  11. #define version "1.0 of 2004-06-20"
  12.  
  13. unsigned char    acc[256];
  14. unsigned char    cart[65536];
  15. const char        *progname;        // pointer to argv[0]
  16. int                testonly;
  17. int                writeback;
  18. unsigned char    fname[256];
  19. FILE            *f;
  20.  
  21. int                starta;
  22. int                offseta;
  23. int                offsetr;
  24. int                sizea;
  25. int                sizer0;
  26. int                sizer1;
  27. int                sizer5;
  28. int                sizer7;
  29. unsigned char    *modmod;
  30. unsigned char    *addmod;
  31. int                adacmod0;
  32. unsigned char    *cmpmod;
  33. int                cpacmod0;
  34. unsigned char    *submod;
  35. int                sbacmod0;
  36. unsigned char    *mdmmod0;
  37. int                mdmmod1;
  38.  
  39. unsigned char    acc[256];
  40. unsigned char    reg0[128];
  41. unsigned char    reg1[128];
  42. unsigned char    reg2[128];
  43. unsigned char    reg3[128];
  44. unsigned char    reg4[128];
  45. unsigned char    reg5[128];
  46. unsigned char    reg6[128];
  47. unsigned char    reg7[128];
  48. unsigned char    reg8[128];
  49. unsigned char    reg9[128];
  50. unsigned char    reg10[128];
  51. unsigned char    reg11[128];
  52. unsigned char    reg12[128];
  53. unsigned char    reg13[128];
  54. unsigned char    reg14[128];
  55.  
  56. char    *evenregs[8] = {reg0,reg2,reg4,reg6,reg8,reg10,reg12,reg14};
  57.  
  58. unsigned char s[] =
  59.     {    0xC7,0x65,0xAB,0xCA,0xEE,0xF7,0x83,0x09,    // note: s and t overlap
  60. //unsigned char t[] =
  61.         0xE1,0xD0,0x92,0x67,0x62,0xB6,0x72,0x55,0x8E,0x91,0xDC,0xC5,0x81,0xBE,0x78,0x20,
  62.         0x59,0xB7,0xE6,0x3D,0x06,0x45,0xAF,0xC8,0x08,0x31,0x38,0xD1,0xFB,0x73,0x84,0xA9,
  63.         0x17,0xFC,0x34,0x87,0xA3,0x94,0xFA,0x90,0xB8,0xED,0xCE,0x3B,0x5B,0x0A,0x43,0xD9,
  64.         0xF3,0x53,0x82,0xB3,0x0D,0x6D,0x5A,0x60,0x9D,0x51,0xA7,0xB9,0x11,0x10,0xBC,0xE4,
  65.         0x7F,0x80,0x41,0xE7,0xE3,0xF6,0x56,0x26,0x35,0xEC,0xD6,0xDF,0x0C,0x7F,0xF4,0x9E,
  66.         0xAC,0x52,0x46,0xEF,0xCF,0xBF,0xA2,0x3F,0xA4,0x13,0x15,0x97,0x4A,0x1C,0xB0,0x42,
  67.         0x8C,0xB1,0x05,0x58,0x80,0x18,0x77,0x2B,0x02,0x3E,0xA8,0x49,0x1A,0x6A,0xCB,0x6E,
  68.         0x0B,0x8A,0xEB,0xF1,0x4F,0x14,0x79,0x8B,0xD8,0x9F,0x9B,0x57,0x19,0xF8,0x2A,0x2D,
  69.         0x76,0x0E,0xE8,0x2E,0x4B,0xF9,0x07,0x03,0xDE,0x93,0x16,0x7E,0xD4,0xE5,0xB2,0xF0,
  70.         0x7D,0x7A,0xDA,0xD2,0xA1,0xCC,0x1D,0xE0,0x5E,0x23,0xA0,0x95,0x22,0x1E,0x36,0x85,
  71.         0xFE,0x1F,0x39,0xAA,0x89,0x96,0xAD,0x0F,0x2F,0xC0,0x47,0x27,0x5D,0x24,0xEA,0xC3,
  72.         0xA5,0xF5,0x21,0x5F,0x1B,0x40,0x8F,0xAE,0x74,0x25,0xDD,0xC1,0x7C,0xCD,0xA6,0x70,
  73.         0xD7,0x33,0x7B,0x2C,0x75,0xBB,0x86,0x99,0xBD,0x54,0x9A,0x6C,0x63,0x32,0x48,0x4C,
  74.         0x8D,0xBA,0x5C,0x61,0xC4,0x4E,0x29,0x37,0x12,0xC6,0x98,0x9C,0xD5,0x69,0x6B,0xE2,
  75.         0x04,0x4D,0xE9,0xC2,0x88,0x3A,0xDB,0x64,0x01,0x44,0x6F,0xB5,0xF2,0x30,0x28,0xFD,
  76.         0x50,0x71,0x3C,0xB4,0x66,0x68,0xC9,0xD3,0xCA,0x83,0xC7,0xAB,0xF7,0x65,0x09,0xEE};
  77.  
  78. char    p[] =
  79.     {    0x70,0x3A,0xC1,0x6F,0x9A,0x92,0xE5,0x29,0x18,0xE7,0x9E,0x50,0xD6,0xA5,0x8D,0xCC,
  80.         0x4D,0x52,0x2A,0xD4,0x5C,0x10,0x71,0x81,0x24,0xCF,0xDA,0x6A,0x4A,0x72,0xEE,0xD5,
  81.         0xCA,0x36,0x1E,0x1B,0x2A,0x20,0xC0,0xDC,0x15,0xE8,0xEE,0x53,0xEB,0xF3,0x2E,0x08,
  82.         0x72,0x59,0x35,0xF8,0x99,0x57,0x3B};
  83.  
  84. char    pexp[] =
  85.     {    0x1C,0x0E,0xB0,0x5B,0xE6,0xA4,0xB9,0x4A,0x46,0x39,0xE7,0x94,0x35,0xA9,0x63,0x73,
  86.         0x13,0x54,0x8A,0xB5,0x17,0x04,0x1C,0x60,0x49,0x33,0xF6,0x9A,0x92,0x9C,0xBB,0xB5,
  87.         0x72,0x8D,0x87,0x86,0xCA,0x88,0x30,0x37,0x05,0x7A,0x3B,0x94,0xFA,0xFC,0xCB,0x82,
  88.         0x1C,0x96,0x4D,0x7E,0x26,0x55,0xCF};
  89.  
  90. char    q[] =
  91.     {    0x16,0x56,0x15,0x79,0x9A,0x53,0x60,0x4F,0x87,0x55,0x9F,0xB2,0x78,0x72,0xE5,0xBC,
  92.         0x7D,0xF8,0x6F,0xCA,0x83,0x2A,0x1F,0xA7,0x63,0xA3,0x55,0x2B,0xD8,0xB8,0x45,0xE2,
  93.         0xA1,0x1F,0x41,0x2B,0x04,0x1B,0x9B,0x5B,0xE1,0x28,0xC5,0xE0,0x6E,0x7D,0xC8,0x0B,
  94.         0x22,0x1E,0xE7,0xD4,0x47,0x4C,0xE5,0xC8,0x92,0x22,0xAD,0xEF,0x70,0x18,0xF1,0x3D,
  95.         0x1B};
  96.  
  97. char    qexp[] =
  98.     {    0x05,0x95,0x85,0x5E,0x66,0x94,0xD8,0x13,0xE1,0xD5,0x67,0xEC,0x9E,0x1C,0xB9,0x6F,
  99.         0x1F,0x7E,0x1B,0xF2,0xA0,0xCA,0x87,0xE9,0xD8,0xE8,0xD5,0x4A,0xF6,0x2E,0x11,0x78,
  100.         0xA8,0x47,0xD0,0x4A,0xC1,0x06,0xE6,0xD6,0xF8,0x4A,0x31,0x78,0x1B,0x9F,0x72,0x02,
  101.         0xC8,0x87,0xB9,0xF5,0x11,0xD3,0x39,0x72,0x24,0x88,0xAB,0x7B,0xDC,0x06,0x3C,0x4F,
  102.         0x47};
  103.  
  104. char    n[] =
  105.     {    0x09,0xCA,0xC9,0xC6,0xB4,0x12,0x08,0x1B,0x60,0x58,0x81,0x4B,0x86,0x01,0xD8,0xBF,
  106.         0xD9,0x25,0xA0,0x7B,0xDC,0x32,0x79,0x84,0x3B,0x7C,0xBC,0x2F,0xE2,0xE2,0xFA,0x8D,
  107.         0x0A,0x00,0x3B,0xC5,0xEC,0xAF,0x2D,0x8A,0xCD,0x06,0x93,0x6A,0xA5,0x14,0x46,0x77,
  108.         0xC4,0x6A,0xB2,0x53,0x36,0xEF,0x8C,0xCE,0x0C,0xA2,0x68,0x71,0xD3,0x73,0xE8,0xF7,
  109.         0x6D,0x06,0xB5,0x20,0xEF,0x23,0x47,0x0C,0x51,0x55,0xC8,0xFE,0xF4,0x58,0xC4,0x3F,
  110.         0x20,0xA7,0x67,0x38,0xB0,0x76,0xE2,0xC4,0xD8,0x05,0x63,0xF8,0x3C,0x58,0x3B,0x2D,
  111.         0x22,0xCC,0x88,0xB3,0x71,0x8F,0x1D,0x80,0x0A,0x87,0xBD,0xA1,0x59,0x23,0xE9,0x70,
  112.         0xE2,0xD3,0xEC,0x46,0x68,0x80,0x42,0x39};
  113.  
  114. char    ap[] =
  115.     {    0x04,0x81,0xBE,0x5B,0x4C,0x70,0x0F,0xBC,0x42,0xA2,0xCD,0x8C,0xE7,0x00,0x26,0x56,
  116.         0xAE,0x76,0x65,0x29,0x3A,0x00,0xD1,0xE6,0xA2,0x9E,0x58,0x77,0x62,0x04,0xF3,0x54,
  117.         0x2A,0x30,0xC3,0x7D,0xDF,0x69,0x9D,0xED,0xC5,0x23,0xB6,0x9D,0x7F,0x18,0xCE,0xF6,
  118.         0x39,0x0F,0x14,0x28,0xF4,0xDF,0xF4,0x98,0xF5,0x20,0xC7,0x64,0xA7,0x7E,0x77,0x0D,
  119.         0x87,0x8D,0x88,0xEB,0xCE,0xD6,0x59,0x63,0xD7,0x70,0xF6,0x4A,0xE6,0xFD,0x83,0x6D,
  120.         0xBC,0x6C,0xEE,0xF6,0x4F,0x88,0x27,0xBD,0xEE,0xBD,0x61,0x5D,0xA5,0xB2,0x5D,0x78,
  121.         0xB0,0xA4,0x71,0x5E,0x05,0xC7,0xBD,0x6E,0xAC,0x4E,0x5B,0x2C,0x89,0x16,0x2B,0x7F,
  122.         0x2F,0xB0,0x7B,0x14,0x64,0x7D,0x44,0xE7};
  123.  
  124. char    aq[] =
  125.     {    0x05,0x49,0x0B,0x6B,0x67,0xA1,0xF8,0x5F,0x1D,0xB5,0xB3,0xBE,0x9F,0x01,0xB2,0x69,
  126.         0x2A,0xAF,0x3B,0x52,0xA2,0x31,0xA7,0x9D,0x98,0xDE,0x63,0xB8,0x80,0xDE,0x07,0x38,
  127.         0xDF,0xCF,0x78,0x48,0x0D,0x45,0x8F,0x9D,0x07,0xE2,0xDC,0xCD,0x25,0xFB,0x77,0x81,
  128.         0x8B,0x5B,0x9E,0x2A,0x42,0x0F,0x98,0x35,0x17,0x81,0xA1,0x0D,0x2B,0xF5,0x71,0xE9,
  129.         0xE5,0x79,0x2C,0x35,0x20,0x4C,0xED,0xA8,0x79,0xE4,0xD2,0xB4,0x0D,0x5B,0x40,0xD1,
  130.         0x64,0x3A,0x78,0x42,0x60,0xEE,0xBB,0x06,0xE9,0x48,0x02,0x9A,0x96,0xA5,0xDD,0xB4,
  131.         0x72,0x28,0x17,0x55,0x6B,0xC7,0x60,0x11,0x5E,0x39,0x62,0x74,0xD0,0x0D,0xBD,0xF1,
  132.         0xB3,0x23,0x71,0x32,0x04,0x02,0xFD,0x53};
  133.  
  134.  
  135. void dump(int n, unsigned char *data)
  136. {
  137.     int    i;
  138.  
  139.     for (i=0; i<n; i++)
  140.     {
  141.         if ((i & 15) == 8) printf("  ");
  142.         else if (i & 15) printf(" ");
  143.         printf("%.2x",data[i]);
  144.         if ((i & 15) == 15) printf("\n");
  145.     }
  146.     printf("\n");
  147.     if (n & 15) printf("\n");
  148. }
  149.  
  150.  
  151. //======================================================
  152.  
  153.  
  154. void setregs(void)  // puts shifted copies of reg0 into even regs reg2..reg14
  155. {
  156.     int i,j,n,carry;
  157.     char *r1,*r2;
  158.  
  159.     offsetr = sizer0 + 1;
  160.     reg0[0] = 0;
  161.  
  162.     for (i = 0; i < 7; i++)
  163.     {
  164.         r1 = evenregs[i];
  165.         r2 = evenregs[i+1];
  166.  
  167.         carry = 0;
  168.         for (j = offsetr; j >= 0; j--)
  169.         {
  170.             n = r1[j] * 2 + carry;
  171.             r2[j] = n & 0xFF;
  172.             carry = (n >> 8) & 1;
  173.         }
  174.     }
  175. }
  176.  
  177.  
  178. void multadd(void)  // acc = acc + addmod
  179. {
  180.     int i,n,carry;
  181.  
  182.     carry = 0;
  183.  
  184.     for (i = offsetr; i >= 0; i--)
  185.     {
  186.         n = acc[i + adacmod0] + addmod[i] + carry;
  187.         acc[i + adacmod0] = n & 0xFF;
  188.         carry = (n >> 8) & 1;
  189.     }
  190.  
  191.     while (carry)
  192.     {
  193.         n = acc[i + adacmod0] + carry;
  194.         acc[i + adacmod0] = n & 0xFF;
  195.         carry = (n >> 8) & 1;
  196.         i--;
  197.     }
  198. }
  199.  
  200.  
  201. void multiply(void) // acc = reg0 * reg1
  202. {
  203.     int i,newoffseta;
  204.  
  205.     setregs();
  206.  
  207.     offseta = sizer1 + 1;
  208.  
  209.     newoffseta = offseta + offsetr;
  210.  
  211.     for (i = 0; i <= newoffseta; i++)
  212.         acc[i] = 0;
  213.  
  214.     adacmod0 = offseta + 1;
  215.  
  216.     while (offseta--)
  217.     {
  218.         adacmod0--;
  219.         for (i = 0; i <= 7; i++)
  220.         {
  221.             if (reg1[offseta] & 1 << i)
  222.             {
  223.                 addmod = evenregs[i];
  224.                 multadd();
  225.             }
  226.         }
  227.     }
  228.     offseta = newoffseta;
  229.     starta = 1;
  230. }
  231.  
  232.  
  233. void divsub(void)   // acc = acc - submod
  234. {
  235.     int i,n,borrow;
  236.  
  237.     borrow = 0;
  238.  
  239.     for (i = offsetr; i >= 0; i--)
  240.     {
  241.         n = acc[i + sbacmod0] - submod[i] - borrow;
  242.         acc[i + sbacmod0] = n & 0xFF;
  243.         borrow = (n >> 8) & 1;
  244.     }
  245.  
  246.     while (borrow)
  247.     {
  248.         n = acc[i + sbacmod0] - borrow;
  249.         acc[i + sbacmod0] = n;
  250.         borrow = (n >> 8) & 1;
  251.         i--;
  252.     }
  253. }
  254.  
  255.  
  256. int divcmp(void)    // returns 1 if acc > cmpmod
  257. {
  258.     int i;
  259.  
  260.     for (i = 0; i < offsetr; i++)
  261.         if (acc[i + cpacmod0] != cmpmod[i])
  262.             return acc[i + cpacmod0] > cmpmod[i];
  263.     return 0;
  264. }
  265.  
  266.  
  267. // this may do division, but it's only used for modulus
  268. // support for saving the quotient has been added as comments
  269. void divide(void)   // acc = acc mod reg0
  270. {
  271.     int i;
  272.  
  273.     setregs();
  274.  
  275. //  char quotient[256];
  276. //    memset(quotient, 0, sizeof(quotient));
  277.  
  278.     starta = offseta = sizea-sizer0;
  279.     cpacmod0 = sbacmod0 = -1;
  280.     acc[0] = 0;
  281.  
  282.     while (offseta--)
  283.     {
  284.         cpacmod0++;
  285.         sbacmod0++;
  286.         for (i = 7; i >= 0; i--)
  287.         {
  288.             cmpmod = submod = evenregs[i];
  289.             if (divcmp())
  290.             {
  291.                 divsub();
  292. //                quotient[offseta+1] |= (1 << i);
  293.             }
  294.         }
  295.     }
  296.     offseta = sizea;
  297. }
  298.  
  299.  
  300. void simplmod(void) // if acc > modmod, acc = acc - modmod
  301. {
  302.     cmpmod = submod = modmod;
  303.     cpacmod0 = sbacmod0 = 1;
  304.  
  305.     if (acc[0] == 0)
  306.         if (!divcmp()) return;
  307.  
  308.     divsub();
  309. }
  310.  
  311.  
  312. void hseroff(void)  // reg0 * reg1 mod mdmmod0
  313. {
  314.     multiply();
  315.  
  316.     sizer0 = mdmmod1;
  317.     memcpy(reg0+1,mdmmod0,sizer0+1);
  318.  
  319.     sizea = offseta;
  320.     divide();
  321. }
  322.  
  323.  
  324. void square(void)   // reg3 * reg3 mod mdmmod0
  325. {
  326.     sizer0 = sizer7;
  327.     memcpy(reg0+1, reg3, sizer7+1);
  328.     sizer1 = sizer7;
  329.     memcpy(reg1,   reg3, sizer7+1);
  330.  
  331.     hseroff();
  332.  
  333.     memcpy(reg3, acc+starta, sizer7+1);
  334. }
  335.  
  336.  
  337. void power(void)    // inputs reg3, reg5, reg7; output reg9
  338. {
  339.     int byt,bit;
  340.  
  341.     mdmmod0 = reg7;
  342.     mdmmod1 = sizer7;
  343.  
  344.     reg9[sizer7] = 1;
  345.     memset(reg9,0,sizer7);
  346.  
  347.     byt = sizer5 + 1;
  348.     while (byt--)
  349.     {
  350.         for (bit = 0; bit <= 7; bit++)
  351.         {
  352.             if (reg5[byt] & (1 << bit))
  353.             {
  354.                 sizer0 = sizer1 = sizer7;
  355.                 memcpy(reg0+1, reg3, sizer7+1);
  356.                 memcpy(reg1,   reg9, sizer7+1);
  357.  
  358.                 hseroff();
  359.  
  360.                 memcpy(reg9, acc+starta, sizer7+1);
  361.             }
  362.             square();
  363.         }
  364.     }
  365.     offsetr = sizer7;
  366. }
  367.  
  368.  
  369. void hashpower(void)    // reg9 = reg11 ^ reg5 mod reg7
  370. {
  371.     memcpy(acc+1, reg11, sizeof(n));
  372.  
  373.     acc[0] = 0;
  374.  
  375.     sizer0 = sizer7;
  376.  
  377.     memcpy(reg0+1, reg7, sizer7+1);
  378.  
  379.     sizea = sizeof(n);
  380.     divide();
  381.  
  382.     memcpy(reg3,acc+starta,sizer7+1);
  383.  
  384.     power();
  385. }
  386.  
  387.  
  388. void dectest(void)        // decrypt hash for validation; acc = reg0 * reg1 mod n
  389. {
  390.     sizer0 = sizeof(n) - 1;
  391.     sizer1 = sizeof(n) - 1;
  392.  
  393.     multiply();
  394.  
  395.     memcpy(reg0+1, n, sizeof(n));
  396.  
  397.     sizea = offseta;
  398.     divide();
  399. }
  400.  
  401.  
  402. // input: cartridge hash in reg11
  403. // output: returns 1 if success and cartridge signature in reg1
  404. int encrypt_hash()
  405. {
  406.     int i,tries;
  407.  
  408.     printf("Encrypting...");
  409.  
  410.     for (tries = 0; tries < 256; tries++)
  411.     {
  412.         printf(" %.2X",reg11[4]);
  413.  
  414.         sizer7 = sizeof(p) - 1;
  415.         memcpy(reg7,p,sizeof(p));            // reg7 = p
  416.         sizer5 = sizeof(pexp) - 1;
  417.         memcpy(reg5,pexp,sizeof(pexp));        // reg5 = pexp
  418.  
  419.         hashpower();                        // reg9 = reg11 ^ reg5 mod reg7
  420.  
  421.         memcpy(reg13,reg9,sizeof(p));        // reg13 = reg9
  422.  
  423.         sizer7 = sizeof(q) - 1;
  424.         memcpy(reg7,q,sizeof(q));            // reg7 = q
  425.         sizer5 = sizeof(qexp) - 1;
  426.         memcpy(reg5,qexp,sizeof(qexp));        // reg5 = qexp
  427.  
  428.         hashpower();                        // reg9 = reg11 & reg5 mod reg7
  429.  
  430.         sizer1 = sizeof(q) - 1;
  431.         memcpy(reg1,reg9,sizeof(q));        // reg1 = reg9
  432.  
  433.         sizer0 = sizeof(aq) - 1;
  434.         memcpy(reg0+1,aq,sizeof(aq));        // reg0[1] = aq
  435.  
  436.         multiply();                            // acc = reg0 * reg1
  437.  
  438.         memcpy(reg0+1,n,sizeof(n));            // reg0[1] = n
  439.  
  440.         sizea = offseta;
  441.         divide();                            // acc = acc mod reg0
  442.  
  443.         memcpy(reg3,acc+starta,sizeof(n));  // reg3 = acc[starta]
  444.  
  445.         sizer1 = sizeof(p) - 1;
  446.         memcpy(reg1,reg13,sizeof(p));        // reg1 = reg13
  447.  
  448.         sizer0 = sizeof(ap) - 1;
  449.         memcpy(reg0+1,ap,sizeof(ap));        // reg0[1] = ap
  450.  
  451.         multiply();                            // acc = reg0 * reg1
  452.  
  453.         memcpy(reg0+1,n,sizeof(n));            // reg0[1] = n
  454.  
  455.         sizea = offseta;
  456.         divide();                            // acc = acc mod reg0
  457.  
  458.         offsetr = sizeof(n) - 1;
  459.         memcpy(acc+1,acc+starta,sizeof(n)); // acc[1] = acc[starta]
  460.  
  461.         addmod = reg3;
  462.         adacmod0 = 1;
  463.         multadd();                            // acc = acc + reg3
  464.  
  465.         modmod = n;
  466.         simplmod();                            // if acc > n, acc = acc - n
  467.  
  468.         memcpy(reg0+1, acc+1, sizeof(n));   // reg0[1] = acc[1]
  469.         memcpy(reg1,   acc+1, sizeof(n));   // reg1 = acc[1]
  470.  
  471.         dectest();                            // try decrypting this signature
  472.  
  473.                                             // compare decrypted signature
  474.         for (i = 0; i < sizeof(n) && acc[i+starta] == reg11[i]; i++);
  475.         if (i == sizeof(n))                    // if decrypted properly...
  476.         {
  477.             printf(" success!\n");
  478.             return 1;                            //return success
  479.         }
  480.  
  481.         reg11[4]++;                            // try encrypting a different number
  482.     }
  483.     printf(" failed!\n");
  484.     return 0;                                // we've tried all possible numbers, so give up
  485. }
  486.  
  487.  
  488. void decrypt_sig(void)
  489. {
  490.     memcpy(reg0+1, cart+0xFF80, sizeof(n));
  491.     memcpy(reg1,   cart+0xFF80, sizeof(n));
  492.  
  493.     dectest();
  494.  
  495.     memcpy(reg1, acc+starta, sizeof(reg1));
  496.  
  497.     reg1[0] = reg1[0] & 0x07;        // zero out the don't-care bits
  498.     reg1[4] = 0;
  499. }
  500.  
  501.  
  502. //======================================================
  503.  
  504.  
  505. void cscheck(int page, unsigned char *perm, int *a, int *carry)
  506. {
  507.     int        i,n;
  508.     int        addr;
  509.  
  510.     addr = page << 8;
  511.     for (i=0; i<256; i++)
  512.     {
  513.         n = *a + acc[i] + *carry;
  514.         *carry = (n >> 8) & 1;
  515.         n = (n & 0xFF) + cart[addr+i] + *carry;
  516.         *a = perm[n & 0xFF];
  517.         acc[i] = *a & 0xFF;
  518.         *carry = (n >> 8) & 1;
  519.     }
  520. }
  521.  
  522.  
  523. void csrotate(int *carry)
  524. {
  525.     int i,n;
  526.  
  527.     for (i=0; i<256; i++)
  528.     {
  529.         n = (acc[i] << 1) + *carry;
  530.         acc[i] = n & 255;
  531.         *carry = (n >> 8) & 1;
  532.     }
  533. }
  534.  
  535.  
  536. void hashcart(void)
  537. {
  538.     int        i,a,carry,startpage;
  539.  
  540.     startpage = cart[0xFFF9] & 0xF0;
  541.  
  542.     memcpy(acc,cart+0xFF00,256);    // copy FFxx page
  543.     memset(acc+0x80,0,0x78);        // zero out signature zone
  544.  
  545.     a = 0;
  546.     carry = 1;
  547.     for (i=startpage; i<=0xFE; i++)
  548.     {
  549.         cscheck(i,s,&a,&carry);        // do s permutation
  550.         carry = 0;
  551.     }
  552.  
  553.     carry = 1;
  554.     csrotate(&carry);
  555.     csrotate(&carry);
  556.  
  557.     for (i=0xFE; i>=startpage; i--)
  558.     {
  559.         cscheck(i,s+8,&a,&carry);   // do t permutation
  560.         carry = 1;
  561.     }
  562.  
  563.     for (i=0; i<=0x77; i++)            // xor the whole mess together
  564.         reg11[i] = acc[i] ^ acc[i+0x50] ^ acc[i+0x88];
  565.  
  566.     reg11[0] = reg11[0] & 0x07;        // zero out the don't-care bits
  567.     reg11[4] = 0;
  568. }
  569.  
  570.  
  571. //======================================================
  572.  
  573.  
  574. void usage(void)
  575. {
  576.     fprintf(stderr,"Atari 7800 digital signature generator - version %s\n",version);
  577.     fprintf(stderr,"by Bruce Tomlin");
  578.     fprintf(stderr,"\n");
  579.     fprintf(stderr,"Usage:\n");
  580.     fprintf(stderr,"    %s [options] image\n",progname);
  581.     fprintf(stderr,"\n");
  582.     fprintf(stderr,"Options:\n");
  583.     fprintf(stderr,"    -t             test existing cartridge signature only\n");
  584.     fprintf(stderr,"    -w             write back update signature to cartridge\n");
  585.     exit(1);
  586. }
  587.  
  588.  
  589. void getopts(int argc, char * const argv[])
  590. {
  591.     int ch;
  592.  
  593.     while ((ch = getopt(argc, argv, "tw?")) != -1)
  594.     {
  595.         switch (ch)
  596.         {
  597.             case 't':
  598.                 testonly = 1;
  599.                 break;
  600.  
  601.             case 'w':
  602.                 writeback = 1;
  603.                 break;
  604.  
  605.             case '?':
  606.             default:
  607.                 usage();
  608.         }
  609.     }
  610.     argc -= optind;
  611.     argv += optind;
  612.  
  613.     // now argc is the number of remaining arguments
  614.     // and argv[0] is the first remaining argument
  615.  
  616.     if (argc != 1)
  617.         usage();
  618.  
  619.     strncpy(fname, argv[0], 255);
  620.  
  621.     // check for conflicting options
  622.     if (testonly && writeback)
  623.         usage();
  624.  
  625.     // note: this won't work if there's a single-char filename in the current directory!
  626.     if (fname[0] == '?' && fname[1] == 0)
  627.         usage();
  628.  
  629. }
  630.  
  631.  
  632. int main (int argc, char * const argv[])
  633. {
  634.     int i,fsize,valid;
  635.  
  636.     setvbuf(stdout, NULL, _IONBF, 0);       // turn off C library file buffering
  637.  
  638.     progname  = argv[0];
  639.     testonly = 0;
  640.     writeback = 0;
  641.     memset(fname,0,sizeof(fname));
  642.     getopts(argc, argv);
  643.  
  644.     f = fopen(fname,"rb");
  645.     if (!f)
  646.     {
  647.         printf("Can't open '%s'!\n",fname);
  648.         exit(1);
  649.     }
  650.  
  651.     // get size of file
  652.     fseek(f, 0, SEEK_END);
  653.     fsize = ftell(f);
  654.     fseek(f, 0, SEEK_SET);
  655.  
  656.     if ((fsize & 0xFFF) != 0 && (fsize & 0x0FFF != 128))
  657.     {
  658.         printf("Cartridge size not a multiple of 4K bytes!\n");
  659.         exit(1);
  660.     }
  661.     if (fsize < 0x1000)
  662.     {
  663.         printf("Cartridge data file must be at least 4K!\n");
  664.         exit(1);
  665.     }
  666.  
  667.     // skip to last 48K of file
  668.     if (fsize > 0xC000)
  669.     {
  670.         fseek(f, fsize-0xC000, SEEK_SET);
  671.         fsize = 0xC000;
  672.     }
  673.  
  674.     // read cartridge data
  675.     i = fread(cart+0x10000-fsize, 1, fsize, f);
  676.     fclose(f);
  677.  
  678.     printf("Read $%.4X bytes of cartridge data.\n",i);
  679.  
  680.     // perform simple validaitions
  681.  
  682.     if ((cart[0xFFF8] & 0xF1) != 0xF1)
  683.     {
  684.         printf("Invalid byte at $FFF8, should be $FF!\n");
  685.         exit(1);
  686.     }
  687.     if (((cart[0xFFF9] & 0xF0) << 8) < 0x10000 - fsize)
  688.     {
  689.         printf("Invalid byte at $FFF9, hash space larger than cartridge image!\n");
  690.         exit(1);
  691.     }
  692.     if ((cart[0xFFF9] & 0x0B) != 3)
  693.     {
  694.         printf("Invalid byte at $FFF9, low nibble should be 3 or 7!\n");
  695.         exit(1);
  696.     }
  697.     if (cart[0xFFFD] < (cart[0xFFF9] & 0xF0))
  698.     {
  699.         printf("Cartridge reset vector points outside hashed area!\n");
  700.         exit(1);
  701.     }
  702.  
  703.     printf("Cartridge hash area is from $%.4X to $FFFF.\n",(cart[0xFFF9] & 0xF0) << 8);
  704.  
  705.     decrypt_sig();
  706.     hashcart();
  707.  
  708.     for (i=0; i<=0x77 && reg1[i] == reg11[i]; i++);
  709.     valid = (i == 0x78);
  710.  
  711.     if (valid)
  712.         printf("Cartridge signature for '%s' is valid!\n",fname);
  713.     else
  714.     {
  715.         for (i=0; i < 0x78 && cart[0xFF80+i]==0; i++);
  716.         if (i == 0x78)
  717.             printf("Cartridge signature for '%s' appears to be empty.\n",fname);
  718.         else
  719.             printf("Cartridge signature for '%s' is not valid!\n",fname);
  720.     }
  721.  
  722.     if (!testonly)
  723.     {
  724.         if (encrypt_hash())
  725.         {
  726.             printf("\nA valid cartridge signature is:\n");
  727.             dump(120,reg1);
  728.  
  729.             if (writeback)
  730.             {
  731.                 if (valid)
  732.                 {
  733.                     printf("Cartridge already has a valid signature, not re-writing file.");
  734.                 }
  735.                 else
  736.                 {
  737.                     f = fopen(fname,"rb+");
  738.                     if (!f)
  739.                     {
  740.                         printf("Can't open '%s' for writing!\n",fname);
  741.                         exit(1);
  742.                     }
  743.  
  744.                     // get size of file
  745.                     fseek(f, 0, SEEK_END);
  746.                     fsize = ftell(f);
  747.                     fseek(f, 0, SEEK_SET);
  748.  
  749.                     fseek(f, fsize-128, SEEK_SET);  // seek to start of signature area
  750.                     i = fwrite(reg1, 1, 120, f);    // write signature
  751.                     printf("Wrote back %d bytes to '%s'.\n",i,fname);
  752.  
  753.                     fclose(f);
  754.                 }
  755.             }
  756.         }
  757.     }
  758.     else exit(1);
  759.  
  760.     return 0;
  761. }